package pers.mihao.quickstream.common.model.result;


import java.io.Serializable;

import static pers.mihao.quickstream.common.model.result.ResultCode.SYSTEM_ERROR;

public class Result<T> implements Serializable {
    private static final long serialVersionUID = 974575393666536043L;
    private boolean success;
    private ResultCode resultCode;
    private T data;

    public Result() {
    }

    public Result(boolean success) {
        this.success = success;
    }

    public Result(boolean success, T data) {
        this.success = success;
        this.data = data;
    }

    public static <T> Result<T> create() {
        return new Result();
    }

    public static <T> Result<T> create(boolean success) {
        return new Result(success);
    }

    public static <T> Result<T> create(Result source) {
        if (source == null) {
            return create(false);
        } else {
            Result result = new Result();
            result.setSuccess(source.isSuccess());
            result.setResultCode(source.getResultCode());
            result.setData(source.getData());
            return result;
        }
    }

    public static <T> Result<T> fail(String message) {
        Result<T> result = create(false);
        result.setResultCode(new ResultCode(SYSTEM_ERROR.getCode(), message));
        return result;
    }

    public static <T> Result<T> fail(ResultCode resultCode) {
        Result<T> result = create(false);
        result.setResultCode(resultCode);
        return result;
    }

    public static <T> Result<T> fail(ResultCodeProvider resultCodeProvider) {
        return fail(resultCodeProvider.getResultCode());
    }

    public static <T> Result<T> success(T data) {
        Result<T> result = create(true);
        result.setData(data);
        return result;
    }

    public static <T> Result<T> success(T data, ResultCode resultCode) {
        Result<T> result = create(true);
        result.setData(data);
        result.setResultCode(resultCode);
        return result;
    }

    public static <T> Result<T> success(T data, ResultCodeProvider resultCodeProvider) {
        return success(data, resultCodeProvider.getResultCode());
    }

    public static boolean isFailure(Result result) {
        return result == null || result.isFailure();
    }

    public static boolean isSuccess(Result result) {
        return result != null && result.isSuccess();
    }

    public static boolean hasData(Result result) {
        return isSuccess(result) && result.getData() != null;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public boolean isSuccess() {
        return this.success;
    }

    public boolean isFailure() {
        return !this.isSuccess();
    }

    public void setResultCode(ResultCode resultCode) {
        this.resultCode = resultCode;
    }

    public void setResultCode(String code, String message) {
        this.setResultCode(new ResultCode(code, message));
    }

    public void setResultCode(int code, String message) {
        this.setResultCode(new ResultCode(code, message));
    }

    public ResultCode getResultCode() {
        return this.resultCode;
    }

    public String getCode() {
        return this.resultCode != null ? this.resultCode.getCode() : null;
    }

    public int getIntCode() {
        return this.resultCode != null ? this.resultCode.getIntCode() : -1;
    }

    public String getMessage() {
        return this.resultCode != null ? this.resultCode.getMessage() : null;
    }

    public void setData(T data) {
        this.data = data;
    }

    public T getData() {
        return this.data;
    }

    public String toString() {
        return String.format("success:%s, resultCode:{%s}", this.success, this.resultCode);
    }
}
